package cn.veliger.mybatis.plugin;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.PropertyRegistry;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;

import javax.xml.bind.DatatypeConverter;
import java.text.SimpleDateFormat;
import java.util.*;

import static org.mybatis.generator.internal.util.StringUtility.isTrue;
import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;

/**
 * @author veliger
 * @create 2018-04-23 2:21
 * @desc
 **/
public class CustomerCommentGenerator implements CommentGenerator {
    /**
     * 属性
     */
    private Properties properties;
    /**
     * 控制日期 不使用日期
     */
    private boolean suppressDate;
    /**
     * 控制所有的注释
     */
    private boolean suppressAllComments;
    /**
     * 添加表注释
     * 如果suppressAllComments为true这个设置将会被忽略
     */
    private boolean addRemarkComments;
    /**
     * 系统属性
     */
    private Properties systemPro;
    /**
     * 时间格式化器
     */
    private SimpleDateFormat dateFormat;
    /**
     * 时间格式化
     */
    private String  dateFormatString;
    /**
     * 作者
     */
    private String author;

    /**
     * 初始化一个默认构造器
     */
    public CustomerCommentGenerator() {
        super();
        properties = new Properties();
        systemPro = System.getProperties();
        suppressDate = false;
        suppressAllComments = false;
        addRemarkComments=true;
        dateFormatString="yyyy-MM-dd HH:mm";
        author = System.getProperties().getProperty("user.name");
    }

    /**
     * java文件级别的注释
     * @param compilationUnit
     */
    public void addJavaFileComment(CompilationUnit compilationUnit) {
        if(suppressAllComments){
            return;
        }
        compilationUnit.addFileCommentLine("/* ");
        compilationUnit.addFileCommentLine("  http://www.veliger.cn");
        compilationUnit.addFileCommentLine("*/");
    }

    /**
     * 给Mapper.xml当生成时候添加一个适当的注释来警告用户该元素是自动生成.
     * @param xmlElement
     */
    public void addComment(XmlElement xmlElement) {
        /*if (suppressAllComments) {
            return;
        }
        xmlElement.addElement(new TextElement("<!--"));
        StringBuilder sb = new StringBuilder();
        xmlElement.addElement(new TextElement("  由MyBatis Generator工具自动生成，请不要手动修改."));
        String s = getDateString();
        if (s != null) {
            sb.setLength(0);
            sb.append("  创建于:");
            sb.append(s);
            sb.append('.');
            xmlElement.addElement(new TextElement(sb.toString()));
        }
        xmlElement.addElement(new TextElement("-->"));*/
    }

    /**
     * 添加文档级别的注释
     * @param rootElement
     */
    public void addRootComment(XmlElement rootElement) {
       /* if(suppressAllComments){
            return;
        }
        rootElement.addElement(new TextElement("<!--"));
        rootElement.addElement(new TextElement("文档级别的注释"));
        rootElement.addElement(new TextElement("-->"));*/
    }

    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) {
            imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); //$NON-NLS-1$
            String comment = "Source Table: " + introspectedTable.getFullyQualifiedTable().toString(); //$NON-NLS-1$
            method.addAnnotation(getGeneratedAnnotation(comment));
    }

    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
        imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); //$NON-NLS-1$
        String comment = "Source field: " //$NON-NLS-1$
                + introspectedTable.getFullyQualifiedTable().toString()
                + "." //$NON-NLS-1$
                + introspectedColumn.getActualColumnName();
        method.addAnnotation(getGeneratedAnnotation(comment));
    }

    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) {
        imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); //$NON-NLS-1$
        String comment = "Source Table: " + introspectedTable.getFullyQualifiedTable().toString(); //$NON-NLS-1$
        field.addAnnotation(getGeneratedAnnotation(comment));
    }

    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
        imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); //$NON-NLS-1$
        String comment = "Source field: " //$NON-NLS-1$
                + introspectedTable.getFullyQualifiedTable().toString()
                + "." //$NON-NLS-1$
                + introspectedColumn.getActualColumnName();
        field.addAnnotation(getGeneratedAnnotation(comment));
    }

    public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) {
        imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); //$NON-NLS-1$
        String comment = "Source Table: " + introspectedTable.getFullyQualifiedTable().toString(); //$NON-NLS-1$
        innerClass.addAnnotation(getGeneratedAnnotation(comment));
    }

    /**
     * 设置属性
     * @param properties
     */
    public void addConfigurationProperties(Properties properties) {
        this.properties.putAll(properties);
        String suppressDateString = properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_DATE);
        if(stringHasValue(suppressDateString)){
            suppressDate=isTrue(suppressDateString);
        }
        String suppressAllCommentsString = properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_ALL_COMMENTS);
        if(stringHasValue(suppressAllCommentsString)){
            suppressAllComments = isTrue(suppressAllCommentsString);
        }
        String addRemarkCommentsString = properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_ADD_REMARK_COMMENTS);
        if(stringHasValue(addRemarkCommentsString)){
            addRemarkComments=isTrue(addRemarkCommentsString);
        }
        String dateFormatStringFromProperties= properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_DATE_FORMAT);
        if(stringHasValue(dateFormatStringFromProperties)){
            dateFormatString = dateFormatStringFromProperties;
        }
        String authorString= properties.getProperty("author");
        if(stringHasValue(authorString)){
            author=authorString;
        }
        if (StringUtility.stringHasValue(dateFormatStringFromProperties)) {
            dateFormat = new SimpleDateFormat(dateFormatString);
        }
    }
    /**
     * 此方法添加自定义javadoc标签。
     * 如果您不希望包含Javadoc标签，那么您可能什么也不做，
     * 然而，如果您不包括Javadoc标记，那么工具插件的Java合并功能将会中断。
     * @param javaElement
     * @param markAsDoNotDelete
     */
    protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete) {
        javaElement.addJavaDocLine(" *");
        StringBuilder sb = new StringBuilder();
        sb.append(" * ");
        if (markAsDoNotDelete) {
            sb.append("由MyBatis Generator工具自动生成，请不要手动修改");
        }
        String s = getDateString();
        if (s != null) {
            sb.append(' ');
            sb.append(s);
        }
        javaElement.addJavaDocLine(sb.toString());
    }

    /**
     * 此方法返回一个格式化日期字符串，用于在Javadoc标记和XML注释中。
     * 如果您不想在这些文档元素中使用日期，则可以返回null。
     * @return 表示当前时间或null的字符串。
     */
    protected String getDateString() {
        if (suppressDate) {
            return null;
        } else if (dateFormat != null) {
            return dateFormat.format(new Date());
        } else {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date());
        }
    }

    /**
     * 内部类字段添加的注释 GeneratedCriteria Criterion
     * @param innerClass
     * @param introspectedTable
     */
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
        if (suppressAllComments) {
            return;
        }
        /*StringBuilder sb = new StringBuilder();
        innerClass.addJavaDocLine("/**");
        innerClass.addJavaDocLine(" * 该内部类类由MyBatis Generator工具自动生成.");
        sb.append(" * 该类对应于数据库表: ");
        sb.append(introspectedTable.getFullyQualifiedTable());
        innerClass.addJavaDocLine(sb.toString());
        addJavadocTag(innerClass, false);
        innerClass.addJavaDocLine(" *\\/");*/
    }

    /**
     * model类的注释
     * @param topLevelClass
     * @param introspectedTable
     */
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        if (suppressAllComments  || !addRemarkComments) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        topLevelClass.addJavaDocLine("/**");
        sb.append(" * @author ");
        if(author!=null){
            sb.append(author);
        }else {
            sb.append(systemPro.getProperty("user.name"));
        }
        topLevelClass.addJavaDocLine(sb.toString());
        sb.setLength(0);
        String s = getDateString();
        if (s != null) {
            sb.append(" * @create ");
            sb.append(s);
            topLevelClass.addJavaDocLine(sb.toString());
        }
        sb.setLength(0);
        String remarks = introspectedTable.getRemarks();
        if (StringUtility.stringHasValue(remarks)) {
            sb.append(" * @desc ");
            String[] remarkLines = remarks.split(systemPro.getProperty("line.separator"));
            for (String remarkLine : remarkLines) {
                sb.append(remarkLine);
            }
            topLevelClass.addJavaDocLine(sb.toString());
            sb.setLength(0);
        }
        sb.append(" * 该类对应于数据库表: ");
        sb.append(introspectedTable.getFullyQualifiedTable());
        topLevelClass.addJavaDocLine(sb.toString());
        topLevelClass.addJavaDocLine(" */");
    }
    /**
     * 内部枚举添加注释
     * @param innerEnum
     * @param introspectedTable
     */
    public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
        if (suppressAllComments) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        innerEnum.addJavaDocLine("/**");
        innerEnum.addJavaDocLine(" * @desc 该枚举由MyBatis Generator生成.");
        sb.append(" * 该枚举对应于数据库表: ");
        sb.append(introspectedTable.getFullyQualifiedTable());
        innerEnum.addJavaDocLine(sb.toString());
        addJavadocTag(innerEnum, false);
        innerEnum.addJavaDocLine(" */");
    }
    /**
     * 表字段添加注释
     * @param field
     * @param introspectedTable
     * @param introspectedColumn
     */
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        if (suppressAllComments) {
            return;
        }
        StringBuffer sb = new StringBuffer();
        field.addJavaDocLine("/**");
        if (introspectedColumn.getRemarks() != null){
            field.addJavaDocLine(" * " + introspectedColumn.getRemarks());
        }
        sb.append(" * 表字段 : ");
        sb.append(introspectedTable.getFullyQualifiedTable());
        sb.append('.');
        sb.append(introspectedColumn.getActualColumnName());
        field.addJavaDocLine(sb.toString());
        field.addJavaDocLine(" */");
    }

    /**
     * 通用字段添加注释
     * @param field
     * @param introspectedTable
     */
    public void addFieldComment(Field field, IntrospectedTable introspectedTable) {

    }
    /**
     * 通用方法注释
     * @param method
     * @param introspectedTable
     */
    public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
        if (suppressAllComments) {
            return;
        }
        method.addJavaDocLine("/**");
        addJavadocTag(method,true);
        String methodName = method.getName();
        if ("deleteByPrimaryKey".equals(methodName)) {
            method.addJavaDocLine(" * 根据主键删除数据库的记录");
        } else if ("insert".equals(methodName)) {
            method.addJavaDocLine(" * 插入数据库记录");
        } else if ("selectByPrimaryKey".equals(methodName)) {
            method.addJavaDocLine(" * 根据主键获取一条数据库记录");
        } else if ("updateByPrimaryKey".equals(methodName)) {
            method.addJavaDocLine(" * 根据主键来更新数据库记录");
        }else if ("updateByPrimaryKeySelective".equals(methodName)) {
            method.addJavaDocLine(" * 根据主键来更新非空数据库记录");
        } else if ("updateByExample".equals(methodName)) {
            method.addJavaDocLine(" * 根据Example更新数据库记录");
        }else if ("updateByExampleSelective".equals(methodName)) {
            method.addJavaDocLine(" * 根据主键来更新非空字段数据库记录");
        } else if ("selectAll".equals(methodName)) {
            method.addJavaDocLine(" * 获取全部数据库记录");
        }else if("deleteByExample".equals(methodName)){
            method.addJavaDocLine(" * 根据Example删除");
        }else if("countByExample".equals(methodName)){
            method.addJavaDocLine(" * 根据Example统计数量");
        }else if("insertSelective".equals(methodName)){
            method.addJavaDocLine(" * 插入一条数据,不插入null");
        }else if("selectByExample".equals(methodName)){
            method.addJavaDocLine(" * 根据Example查找数据");
        }
        method.addJavaDocLine(" *");
        List<Parameter> parameterList = method.getParameters();
        String parameterName;
        for (Parameter parameter : parameterList) {
            parameterName = parameter.getName();
            method.addJavaDocLine(" * @param " + parameterName);
        }
        method.addJavaDocLine(" */");
    }

    /**
     *  添加getter方法注释
     * @param method
     * @param introspectedTable
     * @param introspectedColumn
     */
    public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        StringBuilder sb = new StringBuilder();
        method.addJavaDocLine("/**");
        method.addJavaDocLine(" * @desc 该方法由MyBatis Generator生成.");
        sb.append(" * 该方法返回值对应表: ");
        sb.append(introspectedTable.getFullyQualifiedTable());
        sb.append('.');
        sb.append(introspectedColumn.getActualColumnName());
        method.addJavaDocLine(sb.toString());
        method.addJavaDocLine(" *");
        sb.setLength(0);
        sb.append(" * @return ");
        sb.append(introspectedTable.getFullyQualifiedTable());
        sb.append('.');
        sb.append(introspectedColumn.getActualColumnName());
        method.addJavaDocLine(sb.toString());
        addJavadocTag(method, false);
        method.addJavaDocLine(" */");
    }

    /**
     * Setter方法
     * @param method
     * @param introspectedTable
     * @param introspectedColumn
     */
    public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        if (suppressAllComments) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        method.addJavaDocLine("/**");
        method.addJavaDocLine(" @desc 该方法由MyBatis Generator生成.");
        sb.append(" * 该方法设置的值对应于数据表:");
        sb.append(introspectedTable.getFullyQualifiedTable());
        sb.append('.');
        sb.append(introspectedColumn.getActualColumnName());
        method.addJavaDocLine(sb.toString());
        method.addJavaDocLine(" *");
        Parameter parm = method.getParameters().get(0);
        sb.setLength(0);
        sb.append(" * @param ");
        sb.append(parm.getName());
        sb.append(introspectedTable.getFullyQualifiedTable());
        sb.append('.');
        sb.append(introspectedColumn.getActualColumnName());
        method.addJavaDocLine(sb.toString());
        addJavadocTag(method, false);
        method.addJavaDocLine(" */");
    }

    /**
     * 内部类
     * @param innerClass
     * @param introspectedTable
     * @param markAsDoNotDelete
     */
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
        if (suppressAllComments) {
            return;
        }
        /*StringBuilder sb = new StringBuilder();
        innerClass.addJavaDocLine("/**");
        innerClass.addJavaDocLine(" * @desc 该方法由MyBatis Generator生成.");
        sb.append(" * 该类对应的的数据表为:");
        sb.append(introspectedTable.getFullyQualifiedTable());
        innerClass.addJavaDocLine(sb.toString());
        addJavadocTag(innerClass, markAsDoNotDelete);
        innerClass.addJavaDocLine(" *\\/");*/
    }
    private String getGeneratedAnnotation(String comment) {
        StringBuilder buffer = new StringBuilder();
        buffer.append("@Generated("); //$NON-NLS-1$
        if (suppressAllComments) {
            buffer.append('\"');
        } else {
            buffer.append("value=\""); //$NON-NLS-1$
        }

        buffer.append(MyBatisGenerator.class.getName());
        buffer.append('\"');

        if (!suppressDate && !suppressAllComments) {
            buffer.append(", date=\""); //$NON-NLS-1$
            buffer.append(DatatypeConverter.printDateTime(Calendar.getInstance()));
            buffer.append('\"');
        }

        if (!suppressAllComments) {
            buffer.append(", comments=\""); //$NON-NLS-1$
            buffer.append(comment);
            buffer.append('\"');
        }

        buffer.append(')');
        return buffer.toString();
    }
}
